import { Runner } from './runner';

const PLUGINS = [Runner];

export var Plugins = function(app) {
	const self = this;
	const registerPlugin = plugin => {
		app.plugins[plugin.name] = plugin;
	};

	const getPluginStore = pluginName => {
		if (!self.pluginStorage) self.pluginStorage = {};
		if (!self.pluginStorage[pluginName]) {
			self.pluginStorage = {
				...self.pluginStorage,
				[pluginName]: {},
			};
		}
		return this.pluginStorage[pluginName];
	};
	const setPluginStore = (pluginName, key, val) => {
		const storeVals = { ...getPluginStore(pluginName), [key]: val };
		self.pluginStorage = {
			...self.pluginStorage,
			[pluginName]: storeVals,
		};
	};

	window.addEventListener('yarnLoadedData', e => {
		if (app.data.documentHeader() !== null) {
			const documentHeader = app.data.documentHeader();
			if ('pluginStorage' in documentHeader) {
				self.pluginStorage = documentHeader.pluginStorage;
			}
		}
	});

	const addSettingsItem = ({
		title,
		valueKey,
		defaultValue,
		optionsKey,
		options,
		setterKey,
		settingsColumn,
	}) => {
		app.settings[valueKey] = ko
			.observable(defaultValue)
			.extend({ persist: valueKey });

		app.ui[optionsKey] = options;
		app[setterKey] = function(value, e) {
			const newValue = e ? e.target.value : value;
			app.settings[valueKey](newValue);
		};

		// Dom rendering helper methods
		window.addEventListener('settingsOpened', () => {
			const options = app.ui[optionsKey]
				.map(
					option =>
						`<option value="${option.id}" ${
							option.id === app.settings[valueKey]() ? 'selected="true"' : ''
						}>${option.name}</option>`
				)
				.join('');
			const settingsHtml = `
							<label class="settings-label" for="theme">${title}</label>
							<div class="settings-value markup">
								<select id="mySelect">
									 ${options}
								</select>
							</div>
			`;
			const settingsElement = document.createElement('div');
			settingsElement.className = 'settings-item';
			settingsElement.innerHTML = settingsHtml;
			document
				.getElementById(`settingsColumn${settingsColumn || 'A'}`)
				.appendChild(settingsElement);
			document.getElementById('mySelect').addEventListener('change', e => {
				app[setterKey](false, e);
			});
		});
	};

	const createButton = (
		pluginName,
		{
			name,
			iconName,
			onClick,
			attachTo,
			className,
			title,
			onPointerDown,
			onDoubleClick,
			id,
		}
	) => {
		if (document.getElementById(id) !== null) return;

		const button = document.createElement('span');
		button.id = id || name || title || iconName;
		button.innerHTML = `
			<span class="item ${className || ''}" title="${title || ''}" ${
			onClick ? `onclick="click: app.plugins.${pluginName}.${onClick}"` : ''
		}
			 ${
				 onPointerDown
					 ? ` onpointerdown="app.plugins.${pluginName}.${onPointerDown}"`
					 : ''
			 }
							${
								onDoubleClick
									? `ondblclick="app.plugins.${pluginName}.${onDoubleClick}"`
									: ''
							}
			 >
				<svg class="icon menu-icon icon-file-${iconName} icon-lg icon-fw" style="color:currentColor;"><use xlink:href="public/icons.svg#icon-${iconName}"></use></svg>
				<span class="hide-when-narrow">&nbsp;</span>
				${name || ''}
			</span>
		`;
		document.getElementById(attachTo).appendChild(button);

		return button;
	};

	const createToggle = (
		pluginName,
		{
			id,
			attachTo,
			className,
			title,
			tooltipId,
			toggleValueKey,
			onToggle,
			enableKey,
			iconName,
		}
	) => {
		if (document.getElementById(id) !== null) return;
		const toggleButton = document.createElement('span');
		toggleButton.id = id;
		toggleButton.className = 'styled-checkbox';
		toggleButton.innerHTML = `
						<input class="styled-checkbox" type="checkbox" id="${toggleValueKey}" data-bind="checked: app.plugins.${pluginName}.${enableKey}, event: { change: app.plugins.${pluginName}.${onToggle} }"></input>
						<label for="${toggleValueKey}" title="${title}" class="${className}"><span title="${title}" class="button-bubble" id="${tooltipId}"></span>
							<svg class="icon icon-${iconName} icon-fw icon-lg"><use xlink:href="public/icons.svg#icon-${iconName}"></use></svg>
						</label>
		`;
		document.getElementById(attachTo).appendChild(toggleButton);

		return toggleButton;
	};

	// yarneditor lifecycle events
	const onYarnInPreviewMode = cb => {
		window.addEventListener('yarnSavedNode', e => {
			cb(e);
		});
	};
	const onYarnSavedNode = cb => {
		window.addEventListener('yarnInPreviewMode', e => {
			cb(e);
		});
	};
	const onYarnLoadedData = cb => {
		window.addEventListener('yarnLoadedData', e => {
			cb(e);
		});
	};
	const onYarnSetDocumentType = cb => {
		window.addEventListener('yarnSetDocumentType', e => {
			cb(e);
		});
	};
	const onYarnEditorOpen = cb => {
		window.addEventListener('yarnEditorOpen', e => {
			cb(e);
		});
	};
	const onLoad = cb => {
		window.addEventListener('DOMContentLoaded', e => {
			cb(e);
		});
	};
	const onYarnSetLanguage = cb => {
		window.addEventListener('yarnSetLanguage', e => {
			cb(e);
		});
	};
	const onYarnLoadedStateFromLocalStorage = cb => {
		window.addEventListener('yarnLoadedStateFromLocalStorage', e => {
			cb(e);
		});
	};
	const onYarnSavedStateToLocalStorage = cb => {
		window.addEventListener('yarnSavedStateToLocalStorage', e => {
			cb(e);
		});
	};
	const onKeyUp = cb => {
		$(document).on('keyup', e => {
			cb(e);
		});
	};
	const onKeyDown = cb => {
		$(document).on('keydown', e => {
			cb(e);
		});
	};
	// Todo these are not being cached by the PWA - needs fixing
	// Todo these should also be optional when building - exclude for build-tiny
	// plugin initiation
	PLUGINS.forEach(plugin => {
		const initializedPlugin = new plugin({
			app,
			createButton,
			createToggle,
			getPluginStore,
			setPluginStore,
			addSettingsItem,
			onYarnLoadedData,
			onYarnEditorOpen,
			onYarnInPreviewMode,
			onYarnSavedNode,
			onYarnSetLanguage,
			onYarnLoadedStateFromLocalStorage,
			onYarnSavedStateToLocalStorage,
			onYarnSetDocumentType,
			onKeyUp,
			onKeyDown,
			onLoad,
		});

		window.addEventListener('DOMContentLoaded', e => {
			registerPlugin(initializedPlugin);
		});
	});
};
